/**
 * Copyright (C) 2021 - 2031 O-Cubes Co., Ltd.
 */

/****************************************************************
 *  @file    dlist.h
 *  @brief   Double linked list header file.
 *  @version v1.0
 *  @date    03. Apr. 2023
 ****************************************************************/

#ifndef __DLIST_H__
#define __DLIST_H__

#include <stdlib.h>
#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

/** \defgroup list List Primitives
 *  @{
 */

struct dlist_t {
	struct dlist_t *next, *prev;
};

/*
 * DLIST_NODE_INIT - used for initializing an list elmenet in a static struct
 * or global
 */
#define DLIST_INIT(name) { .next = &name, .prev = &name }
/*
 * DLIST_DECLARE - used for defining and initializing a global or
 * static singleton list
 */
#define DLIST_DECLARE(name)			\
	struct dlist_t name = DLIST_INIT(name)

static inline void dlist_init(struct dlist_t *list)
{
	list->prev = list;
	list->next = list;
}

static inline void dlist_add_before(struct dlist_t *node,
				    struct dlist_t *new_node)
{
	new_node->prev = node->prev;
	new_node->next = node;
	new_node->next->prev = new_node;
	new_node->prev->next = new_node;
}

static inline void dlist_add_after(struct dlist_t *node,
				   struct dlist_t *new_node)
{
	new_node->prev = node;
	new_node->next = node->next;
	new_node->next->prev = new_node;
	new_node->prev->next = new_node;
}

static inline void dlist_add_head(struct dlist_t *list,
				  struct dlist_t *node)
{
	dlist_add_after(list, node);
}

static inline void dlist_add_tail(struct dlist_t *list,
				  struct dlist_t *node)
{
	dlist_add_before(list, node);
}

static inline int dlist_is_empty(struct dlist_t *list)
{
	return list->next == list;
}

static inline void dlist_del(struct dlist_t *node)
{
	node->next->prev = node->prev;
	node->prev->next = node->next;
	node->prev = node;
	node->next = node;
}

static inline struct dlist_t *dlist_first(struct dlist_t *list)
{
	return dlist_is_empty(list) ? NULL : list->next;
}

#define dlist_for_each(list, node)		\
	for ((node) = (list)->next;		\
	     (node) != (list);			\
	     (node) = (node)->next)
/** @} */

#ifdef __cplusplus
}
#endif

#endif /* __LIST_H__ */
